Android Tips #19 ListViewのアイテムでラジオボタン付きのカスタムレイアウトを使う
はじめに
今回はラジオボタンを使った単一選択型の ListView の作りかたを解説したいと思います。 ListViewの基本的な使いかたはこちらを参考にしてください。 下図のような ListView を作ってみたいと思います。
RadioButton付きのアイテムの作りかた
アイテムにはカスタムViewを使うので、まずはカスタムViewに適用するレイアウトを作成します。 今回は ImageView と TextView と RadioButton が含まれた LinearLayout にしてみました。 注意点は RadioButton の android:focusable プロパティと android:clickable プロパティを false にする ところです。この2つのプロパティが true だとアイテムをタップしたときに RadioButton が先にハンドリングしてしまうのでアイテム選択の処理が走りません。
custom_item_view.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:paddingLeft="10dp" android:paddingRight="10dp"> <ImageView android:layout_width="50dp" android:layout_height="50dp" android:padding="4dp" android:src="@drawable/ic_launcher" /> <TextView android:id="@+id/text_view1" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="18sp" android:textColor="@android:color/black" /> <RadioButton android:id="@+id/radio_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:focusable="false" android:clickable="false" /> </LinearLayout>
次にカスタムViewクラスを作ります。カスタムViewのコンストラクタで上記レイアウトを addView() で子として追加します。 ポイントはCheckable インターフェースを実装するというところです。アイテムの View が Checkable インターフェースを実装していると、ListView は選択式のアイテムとして処理してくれます。Checkable インターフェースには isChecked() メソッド、 setChecked() メソッド、 toggle() メソッドがあります。これらのメソッドは ListView でアイテムが選択状態になったときに呼び出されるので、このメソッドを利用し setChecked() メソッド内で RadioButton の setChecked() を変更します。 すると、アイテムが選択されたときに RadioButton の表示を選択状態に切り替えることができます。
CustomItemView.java
package jp.classmethod.android.sample.checkablelistview; import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; import android.widget.Checkable; import android.widget.FrameLayout; import android.widget.RadioButton; public class CustomItemView extends FrameLayout implements Checkable { private RadioButton mRadioButton; public CustomItemView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initialize(); } public CustomItemView(Context context, AttributeSet attrs) { super(context, attrs); initialize(); } public CustomItemView(Context context) { super(context); initialize(); } private void initialize() { // レイアウトを追加する addView(inflate(getContext(), R.layout.custom_item_view, null)); mRadioButton = (RadioButton) findViewById(R.id.radio_button); } @Override public boolean isChecked() { return mRadioButton.isChecked(); } @Override public void setChecked(boolean checked) { // RadioButton の表示を切り替える mRadioButton.setChecked(checked); } @Override public void toggle() { } }
最後に、この View を Adapter で使うためにレイアウトを定義します。あとは ListView の setChoiceMode() を CHOICE_MODE_SINGLE (単一選択モード)にすれば完成です。
list_view_item.xml
<?xml version="1.0" encoding="utf-8"?> <jp.classmethod.android.sample.checkablelistview.CustomItemView xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" />
MainActivity.java
package jp.classmethod.android.sample.checkablelistview; import java.util.ArrayList; import java.util.HashMap; import android.app.Activity; import android.os.Bundle; import android.widget.AbsListView; import android.widget.ListView; import android.widget.SimpleAdapter; public class MainActivity extends Activity { private ListView mListView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SimpleAdapter adapter = new SimpleAdapter(getApplicationContext(), getItemList(), R.layout.list_view_item, new String[] { "title" }, new int[] { R.id.text_view1 }); ListView listView = new ListView(getApplicationContext()); setContentView(listView); listView.setAdapter(adapter); // 単一選択モードにする listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE); // デフォルト値をセットする listView.setItemChecked(0, true); } private ArrayList<HashMap<String, String>> getItemList() { ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>(); HashMap<String, String> item1 = new HashMap<String, String>(); item1.put("title", "リュウレンジャー"); list.add(item1); HashMap<String, String> item2 = new HashMap<String, String>(); item2.put("title", "シシレンジャー"); list.add(item2); HashMap<String, String> item3 = new HashMap<String, String>(); item3.put("title", "テンマレンジャー"); list.add(item3); HashMap<String, String> item4 = new HashMap<String, String>(); item4.put("title", "キリンレンジャー"); list.add(item4); HashMap<String, String> item5 = new HashMap<String, String>(); item5.put("title", "ホウオウレンジャー"); list.add(item5); HashMap<String, String> item6 = new HashMap<String, String>(); item6.put("title", "キバレンジャー"); list.add(item6); return list; } }
また、setChecked() メソッド内に処理を書き足せば RadioButton 以外の View も自由に変更することができます。 以下の例では背景と文字色を変更してみました。
@Override public void setChecked(boolean checked) { // RadioButton の表示を切り替える mRadioButton.setChecked(checked); TextView textView = (TextView) findViewById(R.id.text_view1); textView.setTextColor(checked ? Color.WHITE : Color.BLACK); setBackgroundColor(checked ? Color.DKGRAY : Color.TRANSPARENT); }
ListView を Spinner に置き換えることもできます!
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SimpleAdapter adapter = new SimpleAdapter(getApplicationContext(), getItemList(), R.layout.list_view_item, new String[] { "title" }, new int[] { R.id.text_view1 }); // Spinner の場合 setContentView(R.layout.layout_main); Spinner spinner = (Spinner) findViewById(R.id.spinner); spinner.setAdapter(adapter); }
ソースコード
今回実装したソースコードを github で共有しています!ぜひ参考にしていただければと思います。
suwa-yuki/CheckableListViewSample
まとめ
今回は単一選択型の ListView でカスタムレイアウトを使う方法をご紹介しましたが、
複数選択型(チェックボックス付き)の ListView もほぼ同じ方法で実装することができます。変わるところは カスタムView の RadioButton が CheckBox になる点と、 ListView の setChoiceMode() の引数が CHOICE_MODE_MULTIPLE になる点くらいです。
よく必要になる実装だと思うので、参考にしていただければ幸いです。また AlertDialog でも実装できるので、応用編としてぜひ試してみてください。